﻿// =====================================================================
//
//  This file is part of the Microsoft Dynamics CRM SDK code samples.
//
//  Copyright (C) Microsoft Corporation.  All rights reserved.
//
//  This source code is intended only as a supplement to Microsoft
//  Development Tools and/or on-line documentation.  See these other
//  materials for detailed information regarding Microsoft code samples.
//
//  THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//
// =====================================================================

using System;
using System.Globalization;
using System.ServiceModel;
using System.Xml;
using System.Xml.Linq;

namespace SL.IdentityModel.Protocols.WSTrust
{
	/// <summary>
	/// Class performs WSTrust 13 RequestSecurityToken serialization to XML
	/// </summary>
	internal class WSTrust13SerializationHelper
	{
		private const string Address = "Address";
		private const string AppliesTo = "AppliesTo";
		private const string EndpointReference = "EndpointReference";
		private const string nsAddressing = "http://www.w3.org/2005/08/addressing";
		private const string nsPolicy = "http://schemas.xmlsoap.org/ws/2004/09/policy";
		private const string prefixAddressing = "a";
		private const string prefixPolicy = "wsp";

		private XNamespace namespaceUri;

		internal WSTrust13SerializationHelper(XNamespace namespaceUri)
		{
			this.namespaceUri = namespaceUri;
		}

		/// <summary>
		/// Writes RequestSecurityToken to writer
		/// </summary>
		/// <param name="rst">RequestSecurityToken to be written to XML</param>
		/// <param name="writer">XmlWriter XML is written to</param>
		public void WriteRST(RequestSecurityToken rst, XmlWriter writer)
		{
			if (rst.AppliesTo != null)
			{
				WriteAppliesTo(writer, rst.AppliesTo);
			}
			if (!string.IsNullOrEmpty(rst.RequestType))
			{
				WriteRequestType(writer, rst.RequestType);
			}
			if (null != rst.EntropyBytes)
			{
				WriteEntropy(writer, rst.EntropyBytes);
			}
			if (!string.IsNullOrEmpty(rst.KeyType))
			{
				WriteKeyType(writer, rst.KeyType);
			}
			if (null != rst.KeySizeInBits && rst.KeySizeInBits.HasValue)
			{
				WriteKeySizeInBits(writer, rst.KeySizeInBits.Value);
			}
		}

		internal void WriteKnownRequestElement(RequestSecurityToken rst, XmlWriter writer)
		{
			WriteRST(rst, writer);
		}

		internal void WriteXml(RequestSecurityToken request, System.Xml.XmlWriter writer)
		{
			WriteRequest(request, writer);
		}

		public void WriteRequest(RequestSecurityToken rst, XmlWriter writer)
		{
			writer.WriteStartElement(WSTrust13Constants.Prefix, WSTrust13Constants.ElementNames.RequestSecurityToken, this.namespaceUri.NamespaceName);
			WriteKnownRequestElement(rst, writer);
			writer.WriteEndElement();
		}

		private void WriteKeyType(XmlWriter writer, string keyType)
		{
			writer.WriteElementString(WSTrust13Constants.Prefix, WSTrust13Constants.ElementNames.KeyType, this.namespaceUri.NamespaceName, keyType);
		}

		private void WriteAppliesTo(XmlWriter writer, EndpointAddress appliesTo)
		{
			writer.WriteStartElement(prefixPolicy, AppliesTo, nsPolicy);
			writer.WriteStartElement(prefixAddressing, EndpointReference, nsAddressing);
			writer.WriteStartElement(prefixAddressing, Address, nsAddressing);
			writer.WriteString(appliesTo.Uri.AbsoluteUri);
			writer.WriteEndElement();
			writer.WriteEndElement();
			writer.WriteEndElement();
		}

		private void WriteEntropy(XmlWriter writer, byte[] entropyBytes)
		{
			if (entropyBytes != null)
			{
				writer.WriteStartElement(WSTrust13Constants.ElementNames.Entropy, this.namespaceUri.NamespaceName);
				writer.WriteStartElement(WSTrust13Constants.ElementNames.BinarySecret, this.namespaceUri.NamespaceName);
				writer.WriteString(Convert.ToBase64String(entropyBytes));
				writer.WriteEndElement();
				writer.WriteEndElement();
			}
			return;
		}

		private void WriteKeySizeInBits(XmlWriter writer, int keySizeInBits)
		{
			writer.WriteElementString(WSTrust13Constants.Prefix, WSTrust13Constants.ElementNames.KeySize, this.namespaceUri.NamespaceName, Convert.ToString(((int)keySizeInBits), CultureInfo.InvariantCulture));
		}

		private void WriteRequestType(XmlWriter writer, string requestType)
		{
			writer.WriteElementString(WSTrust13Constants.Prefix, WSTrust13Constants.ElementNames.RequestType, this.namespaceUri.NamespaceName, requestType);
		}

	}

}
